package com.freecloud.framework.repository;

import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;

import static org.springframework.data.jpa.repository.query.QueryUtils.*;

/**
 * @Author: maomao
 * @Date: 2019-08-01 18:03
 */
public class BaseDaoImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseDao<T, ID> {

    private final JpaEntityInformation<T, ?> entityInformation;
    private final EntityManager em;
    private final PersistenceProvider provider;

    public BaseDaoImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);

        this.entityInformation = entityInformation;
        this.em = entityManager;
        this.provider = PersistenceProvider.fromEntityManager(entityManager);
    }

    public BaseDaoImpl(Class<T> domainClass, EntityManager em) {
        this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
    }


    @Override
    public int deleteBatch(ID[] ids) {
        Assert.notNull(ids, "The given Iterable of ids not be null!");

        if (ids == null || ids.length < 1) {
            return 0;
        }
        return applyInBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), Arrays.asList(ids), em)
                .executeUpdate();
    }


    public static <T> Query applyInBind(String queryString, Iterable<T> entities, EntityManager entityManager) {

        Assert.notNull(queryString, "Querystring must not be null!");
        Assert.notNull(entities, "Iterable of entities must not be null!");
        Assert.notNull(entityManager, "EntityManager must not be null!");

        Iterator<T> iterator = entities.iterator();

        if (!iterator.hasNext()) {
            return entityManager.createQuery(queryString);
        }

        String alias = detectAlias(queryString);
        StringBuilder builder = new StringBuilder(queryString);
        builder.append(" where " + alias + " in ( ");

        int i = 0;

        while (iterator.hasNext()) {

            iterator.next();

            builder.append(String.format(" ?%d", alias, ++i));

            if (iterator.hasNext()) {
                builder.append(" ,");
            }
        }

        builder.append(" )");

        Query query = entityManager.createQuery(builder.toString());

        iterator = entities.iterator();
        i = 0;

        while (iterator.hasNext()) {
            query.setParameter(++i, iterator.next());
        }

        return query;
    }
}
